﻿using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using MiniCap.Abstractions;
using System.Reflection;

namespace MiniCap.Infrastructure;

public sealed class SubscriptionManager
{
    private readonly ILogger<SubscriptionManager> _logger;
    private readonly IServiceProvider _sp;


    private readonly Dictionary<string, List<(Type type, MethodInfo method)>> _handlers = new();


    public SubscriptionManager(ILogger<SubscriptionManager> logger, IServiceProvider sp)
    {
        _logger = logger; _sp = sp;
        Scan(AppDomain.CurrentDomain.GetAssemblies());
    }


    private void Scan(IEnumerable<Assembly> assemblies)
    {
        foreach (var asm in assemblies)
        {
            foreach (var type in asm.GetTypes())
            {
                foreach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic))
                {
                    if (MiniCapSubscribeAttribute.TryFromMethod(method, out var topic) && topic != null)
                    {
                        _handlers.TryAdd(topic, new());
                        _handlers[topic].Add((type, method));
                        _logger.LogInformation("MiniCap subscribed: {Type}.{Method} -> {Topic}", type.FullName, method.Name, topic);
                    }
                }
            }
        }
    }


    public async Task InvokeHandlersAsync(string topic, string? body, IDictionary<string, string> headers, CancellationToken ct)
    {
        if (!_handlers.TryGetValue(topic, out var list)) return;
        foreach (var (type, method) in list)
        {
            using var scope = _sp.CreateScope();
            var target = scope.ServiceProvider.GetRequiredService(type);
            var parameters = method.GetParameters();
            object?[] args = new object?[parameters.Length];


            for (int i = 0; i < parameters.Length; i++)
            {
                var p = parameters[i];
                if (p.ParameterType == typeof(string)) args[i] = body;
                else if (p.ParameterType == typeof(CancellationToken)) args[i] = ct;
                else if (p.ParameterType == typeof(IDictionary<string, string>)) args[i] = headers;
                else if (body != null)
                {
                    // 尝试 JSON 反序列化
                    args[i] = System.Text.Json.JsonSerializer.Deserialize(body, p.ParameterType);
                }
            }


            var result = method.Invoke(target, args);
            if (result is Task t) await t.ConfigureAwait(false);
        }
    }
}

